package monitor

import (
	"gitee.com/ymofen/gobase"
	"sync"
	"sync/atomic"
)

type Monitor interface {
	Calcu()
	Reset()
}

type IntervalEngineer interface {
	SetInterval(fn func())
}

type monitorMgr struct {
	lk  sync.RWMutex
	lst map[Monitor]*monitorWrapper
}

type monitorWrapper struct {
	addsn uint32
	id    interface{}
	sn    int
	rec   Monitor
}

var (
	lk                sync.Mutex
	defaultMonitorMgr = &monitorMgr{lst: make(map[Monitor]*monitorWrapper)}
	intervalEnginner  IntervalEngineer
	sn                atomic.Uint32
)

func SetIntervalEngineer(engine IntervalEngineer) {
	lk.Lock()
	defer lk.Unlock()
	if intervalEnginner != engine {
		if intervalEnginner != nil {
			intervalEnginner.SetInterval(nil)
			gobase.TryClose(intervalEnginner)
		}
		intervalEnginner = engine
		intervalEnginner.SetInterval(defaultMonitorMgr.calcu)
	}
}

func (this *monitorMgr) calcu() {
	this.lk.RLock()
	defer this.lk.RUnlock()
	for m, _ := range this.lst {
		m.Calcu()
	}
	return
}

func (this *monitorMgr) AddMonitor(m Monitor) {
	this.lk.Lock()
	defer this.lk.Unlock()
	this.lst[m] = &monitorWrapper{sn.Add(1), m, 0, m}
}

func (this *monitorMgr) RemoveMonitor(m Monitor) {
	this.lk.Lock()
	defer this.lk.Unlock()
	rec := this.lst[m]
	if rec != nil {
		rec.rec = nil
		rec.id = nil
	}
	delete(this.lst, m)
}

func (this *monitorMgr) Reset() {
	this.lk.RLock()
	defer this.lk.RUnlock()
	for m, _ := range this.lst {
		m.Reset()
	}
}

func AddMonitor(m Monitor) {
	defaultMonitorMgr.AddMonitor(m)
}

func RemoveMonitor(m Monitor) {
	defaultMonitorMgr.RemoveMonitor(m)
}
